﻿// owner 蒋家伟

#include "UniqueId.h"

// std
#include "StringUtils.h"
#include "BitoperationUtils.h"

using namespace jsdk;

#ifdef _WINDOWS
#include <windows.h>
namespace
{
    Uid create()
    {
        Uid res;
        GUID guid;
        if (!CoCreateGuid(&guid))
        {
            res.data1 = guid.Data1;
            res.data2 = guid.Data2;
            res.data3 = guid.Data3;
            std::memcpy(&res.data4, &guid.Data4, sizeof(res.data4));
        }
        return res;
    }
}
#else
#error 其他系统暂未支持
#endif // _WINDOWS
#include "HashUtils.h"

namespace
{
    bool check_is_Hex_String(const std::string& str)
    {
        for (int i = 0; i < str.size(); i++)
        {
            short value = (str[i] - L'0');
            if (value >= 0 && value < 10)
            {
                continue;
            }
            value = (str[i] - L'A');
            if (value >= 0 && value < 6)
            {
                continue;
            }

            value = (str[i] - L'a');
            if (value > 0 && value < 6)
            {
                continue;
            }
            return false;
        }
        return true;
    }
}

#define UNIQUE_ID_SIZE 38

UniqueId UniqueId::s_InvalidUId = UniqueId();

jsdk::UniqueId::UniqueId()
{

}

jsdk::UniqueId & jsdk::UniqueId::operator=(const UniqueId& uid)
{
    m_uid = uid.m_uid;
    return *this;
}

jsdk::UniqueId::UniqueId(const UniqueId& uid):
    m_uid(uid.m_uid)
{

}

bool jsdk::UniqueId::operator<(const UniqueId& uid) const
{
    return std::memcmp(&this->m_uid, &uid.m_uid, sizeof(this->m_uid)) < 0;
}

bool jsdk::UniqueId::operator>(const UniqueId& uid) const
{
    return std::memcmp(&this->m_uid, &uid.m_uid, sizeof(this->m_uid)) > 0;
}

bool jsdk::UniqueId::operator==(const UniqueId& uid) const
{
    return std::memcmp(&this->m_uid, &uid.m_uid, sizeof(this->m_uid)) == 0;
}

bool jsdk::UniqueId::operator!=(const UniqueId& uid) const
{
    return !(*this == uid);
}

jsdk::UniqueId jsdk::UniqueId::create()
{
    UniqueId res;
    res.m_uid = ::create();
    return res;
}

jsdk::UniqueId jsdk::UniqueId::fromWString(const std::wstring& uidStr)
{
    if (uidStr.empty() || uidStr.size() != UNIQUE_ID_SIZE || uidStr.front()!= L'{' || uidStr.back() != L'}')
    {
        return s_InvalidUId;
    }
    else
    {
        // 数据的check
        // 从字符构造uniqueId
        std::string tempStr = StringUtils::toString(uidStr);
        std::string strArray[4]{};
        strArray[0].swap(tempStr.substr(1, 8));
        strArray[1].swap(tempStr.substr(10, 4));
        strArray[2].swap(tempStr.substr(15, 4));
        strArray[3].swap(tempStr.substr(20, 4)) ;
        strArray[3] += tempStr.substr(25, 12);

        for (int i = 0; i < 4; i++)
        {
            if (!check_is_Hex_String(strArray[i]))
                return s_InvalidUId;
        }

        UniqueId res;
        res.m_uid.data1 = StringUtils::HexStringToIntegral<uint32_t>(strArray[0]);
        res.m_uid.data2 = StringUtils::HexStringToIntegral<uint16_t>(strArray[1]);
        res.m_uid.data3 = StringUtils::HexStringToIntegral<uint16_t>(strArray[2]);
        union
        {
            uint64_t data4;
            uint8_t data[8];
        } t;
        t.data4 = StringUtils::HexStringToIntegral<uint64_t>(strArray[3]);
        for (int i = 0; i < 8; i++)
        {
            res.m_uid.data4[i] = t.data[8 - i - 1];
        }
        return res;
    }
    return s_InvalidUId;
}

bool jsdk::UniqueId::isValid() const
{
    return s_InvalidUId != *this;
}

std::wstring jsdk::UniqueId::toString() const
{
    char buf[UNIQUE_ID_SIZE + 1]{};
    sprintf_s(buf,
        "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
        m_uid.data1,
        m_uid.data2,
        m_uid.data3,
        m_uid.data4[0],
        m_uid.data4[1],
        m_uid.data4[2],
        m_uid.data4[3],
        m_uid.data4[4],
        m_uid.data4[5],
        m_uid.data4[6],
        m_uid.data4[7]
    );
    return StringUtils::toWString(buf);
}

const jsdk::Uid& jsdk::UniqueId::getUid() const
{
    return m_uid;
}

size_t jsdk::Hash_UniqueId::operator()(const UniqueId& uniqueId) const
{
    const Uid& uid = uniqueId.getUid();
    return HashUtils::bit_hash((const unsigned char*)&uid, sizeof(Uid));
}
